import { _decorator, Component, Node, Sprite, SpriteFrame, UIOpacity, v3, Vec3 } from 'cc';
import GlobalPool from '../../Init/Tools/GlobalPool';
import Loader from '../../Init/Tools/Loader';
const { ccclass, property } = _decorator;

const tmpP1 = v3();
const tmpV1 = v3();
// 喷射彩虹效果
@ccclass('RibbonEffectLayer')
export class RibbonEffectLayer extends Component {
    @property(Node)
    effectLayer: Node = null;
    @property(Node)
    direcLayer: Node = null;

    effectArr: RibbonItem[] = [];
    spriteFrameArr: SpriteFrame[] = [];
    isLoadFinish = false;
    // 发射位置和方向
    posArr: { p: Vec3, v: Vec3 }[] = [];
    // 发射时间间隔-随机
    @property
    shotCd = 0.02;
    @property
    shotCount = 15; // 发射次数

    curt = 0;
    curCount = 0;
    //
    @property
    delayTime = 0.5;
    curDelay = 0;

    onLoad(): void {
        // 计算发射方向
        for (let i = 0; i < this.direcLayer.children.length; i++) {
            const e = this.direcLayer.children[i];

            tmpV1.set(1, 0, 0);
            Vec3.rotateZ(tmpV1, tmpV1, Vec3.ZERO, 0.01745 * e.angle);
            tmpV1.normalize();

            this.posArr.push({
                p: v3(e.position),
                v: v3(tmpV1)
            });
        }
        this.loadSprite();
    }

    onEnable() {
        // 回收
        GlobalPool.putAllChildren(this.effectLayer);
        // 更新发射位置
        for (let i = 0; i < this.direcLayer.children.length; i++) {
            this.posArr[i].p.set(this.direcLayer.children[i].position);
        }

        this.curCount = this.shotCount;
        this.curt = 0;
        this.curDelay = this.delayTime;
        this.shotCd = 0.02;
    }

    onDisable(): void {
        for (let i = 0; i < this.effectArr.length; i++) {
            this.effectArr[i].reset();
        }
        this.effectArr.length = 0;

    }

    update(dt: number) {
        this.curDelay -= dt;

        if (this.curDelay <= 0) {
            this.curDelay = 0;
        }

        if (!this.isLoadFinish || this.curDelay > 0) return;

        if (this.curCount > 0) {
            this.curt += dt;
            if (this.curt >= this.shotCd) {
                this.curt = 0;
                this.curCount--;
                // 单次发射数量
                let n = 1;
                // 发射进度
                let r = Math.sin((this.curCount / this.shotCount) * Math.PI);
                // 数量根据进度变化
                n += Math.floor((r + 1) * 3);

                this.createRibbon(n, r);
                //随机cd
                this.shotCd = Math.random() * 0.01 + 0.01;
            }
        }

        for (let i = this.effectArr.length - 1; i >= 0; i--) {
            const e = this.effectArr[i];
            if (e.isFinish) {
                e.reset();
                this.effectArr.splice(i, 1);
            } else {
                e.update(dt);
            }
        }
    }
    ribbonEffect = 'ribbonEffect';
    createRibbon(n, rate) {
        // 发散角度
        let r = 30 * 0.01745;
        // 发散角度第增值-
        let addr = 2 * 0.01745 * (this.shotCount - this.curCount) * rate;

        // 发射速度
        let spd = Math.random() * 1000 * rate + 3000;

        let _name = this.ribbonEffect;

        for (let i = 0; i < this.posArr.length; i++) {
            const e = this.posArr[i];
            // 判断发射点方向
            let sign = Math.sign(e.p.x);

            for (let j = 0; j < n; j++) {
                let item = GlobalPool.get(_name);
                this.effectLayer.addChild(item);
                const cmp = new RibbonItem(item);
                // 速度随机偏转
                tmpV1.set(e.v);
                Vec3.rotateZ(tmpV1, tmpV1, Vec3.ZERO, (Math.random() * 2 - 1) * r + addr * sign);
                tmpV1.normalize().multiplyScalar(spd);
                // 坐标随机偏移
                tmpP1.set(e.p);
                tmpP1.x += Math.random() * 80 - 40;
                tmpP1.y += Math.random() * 80 - 40;

                let sf = this.spriteFrameArr[Math.floor(Math.random() * this.spriteFrameArr.length)];
                cmp.init(tmpP1, tmpV1, 1, sf);
                this.effectArr.push(cmp);
            }
        }

    }

    // 加载图片
    loadSprite() {
        Loader.loadBundleDir('UI', 'Assets/Images/common/ribbonEffect', (arr: SpriteFrame[]) => {
            for (let i = 0; i < arr.length; i++) {
                this.spriteFrameArr.push(arr[i]);
            }
            this.isLoadFinish = true;
        }, SpriteFrame)
    }
}

export class RibbonItem {
    node: Node;
    uiopacity: UIOpacity;
    sprite: Sprite = null;

    pos: Vec3 = v3();
    spd: Vec3 = v3();
    spdLerp = 0.01;
    scale: number = 1;
    opacity: number = 0;    // 0-1

    isFinish: boolean = false;
    g = -500;
    //
    curt = 0;
    //
    angle = 0;
    angleSpd = 0;

    constructor(node: Node) {
        this.node = node;
        this.uiopacity = this.node.getComponent(UIOpacity);
        this.sprite = this.node.getComponent(Sprite);
    }
    init(initPos: Vec3, spd: Vec3, scale: number, sf: SpriteFrame) {
        this.opacity = 1;
        this.pos.set(initPos);
        this.spd.set(spd);
        this.sprite.spriteFrame = sf;
        this.scale = scale;
        this.curt = 0;
        this.spdLerp = Math.random() * 0.02 + 0.04;

        this.isFinish = false;
        this.node.setPosition(this.pos);
        this.node.setScale(this.scale, this.scale, 1);

        this.angleSpd = 360 + (Math.random() * 2 - 1) * 60;
        this.angle = (Math.random() + 2) * 360;
        this.node.angle = this.angle;

        this.uiopacity.opacity = 255;
    }

    reset() {
        GlobalPool.put(this.node);
        this.node = null;
    }

    update(dt) {
        if (this.isFinish) {
            return;
        }
        // 动画时长
        this.curt += dt;

        this.spd.lerp(Vec3.ZERO, this.spdLerp);
        // 位移
        this.spd.y += this.g * dt;
        this.pos.add(tmpV1.set(this.spd).multiplyScalar(dt));
        this.node.setPosition(this.pos);

        // 缩放
        if (this.curt < 1) {
            this.scale += 1 * dt;
            this.node.setScale(this.scale, this.scale);
        }

        // 角度
        this.angleSpd -= this.angleSpd * 0.01;
        this.angle -= this.angleSpd * dt;
        if (this.angle < 0) {
            this.angle = 0;
        }
        this.node.angle = this.angle;

        // 透明度
        if (this.curt > 1.5 && this.opacity > 0) {
            this.opacity -= 0.6 * dt;
            if (this.opacity <= 0) {
                this.opacity = 0;
            }
            this.uiopacity.opacity = this.opacity * 255;
        }

        if (this.opacity <= 0) {
            this.isFinish = true;
        }
    }

}
